The game kernel (STARFLT.COM) is actually a FORTH interpreter configured to automatically run a pre-defined word on startup.
This interpreter seems to be a custom FORTH tailored for Starflight, as this startup message shows:
FORTHOUGHT (P) (C) Copyright Fantasia Systems Inc. 1982,1983,1984 Version 2.52 for Binary Systems for the IBM PC
Binary Systems is the company that released Starflight. FORTHOUGHT may have existed as a standalone product,
but I could not find references to it. Fantasia Systems still exists,
although I think they do not work with FORTH anymore.
Dissecting the interpreter revealed a FORTH dictionary of 1956 words, of which 1750 were coded in FORTH and 206 in x86 Assembly.
Because of the way the dictionary is implemented it is not trivial to trace all the words, so there may be a few more.
Another feature is that not all words are named. The process of generating the final kernel may have striped some word names,
but it is not clear why some names were removed and other names remained. Of the total 1956 words, 276 are unamed.
The remaining 1680 words are named, but it seems they employed some obfuscation method to hide the names:
every character of word names was XOR’ed with 0x7F. This process can be reversed and the interpreter remains functional after
decoding the word names.
About the interpreter itself this is what I found:
- It obviously predates the 1994 ANS FORTH standard, but may be FORTH-79 compatible.
- It uses Indirect Threaded Code (ITC).
- Cells are 16-bits wide.
- The parameter stack is implemented with the x86 hardware stack, so register SP points to the stack top.
- The return stack is implemented with register BP.
- The instruction pointer is implemented with register SI.
- Control flow words are implemented with BRANCH and 0BRANCH words.
As an example, here is the Assembly definition of the FORTH word “@” (fetch):
POP BX ; pops the address from the parameter stack PUSH WORD PTR [BX] ; pushes the cell contained in the address LODSW MOV BX,AX JMP WORD PTR [BX]
The code starting with LODSW is in FORTH jargon known as the NEXT routine.
It fetches the next FORTH word pointed to by the instruction pointer (SI) and jumps to its code field.
Also as an example, here is the colon definition of the FORTH word MAX, reconstructed from the dictionary:
: MAX 2DUP < IF SWAP THEN DROP ;
A directory entry for a named colon definition has the following fields:
- Link field: 2 bytes pointing back to the name field of the previous FORTH word in the vocabulary.
- Name field: the first byte is used as follows: bit 7 is always 1, bit 6 the IMMEDIATE flag, bit 5 is the SMUDGE flag, bits 0-4 store the word length. Then there is a variable number of bytes, each one XOR’ed with 0x7F. The last byte of the word name is OR’ed with 0×80 to signal the name end.
- Code field: 2 bytes pointing to the machine language code to run this word.
- Parameter field: variable number of code field addresses, each one occupying 2 bytes. The last one is always the code field address of word EXIT.
An unamed word has only a code field and a parameter field, meaning that unamed words can not be followed by other words in vocabulary. In a machine language word, the code field points to the parameter field, and the parameter field has x86 assembly code ended the the NEXT routine.
The first word executed by the interpreter is a unamed word (unamed
words are shown here as a 4 digit hex number surrounded brackets, and
number literals are shown in hex).
Its colon definition is:
:
(SETUP) (CS?) DS ! f2d2 PSW ! 701 OPERATOR 74 CMOVE
DP @ INITIAL-DP ! 'FORTH CONTEXT ! DEFINITIONS FREEZE
AUTO-LIMIT AUTO-CACHE
SP! RP! SET-BUFFERS AUTO-SCREEN
BOOT-HOOK @ ?DUP IF
EXECUTE
THEN
BOOT-LOAD @ ?DUP IF
LOAD
THEN
ABORT
;
Of importance here is the section that tests the variable BOOT-HOOK. If
the cell stored in this variable is not zero, it is assumed
to contain the address of a FORTH word to be EXECUTEd. In the kernel shipped with Starflight the variable BOOT-HOOK contains
the address of a word named LET-THERE-BE-STARFLIGHT. As the name implies, this word starts the game.
If the kernel is patched to zero this variable, the interpreter will not
execute it and will proceed up to the last word, which is ABORT.
Contrary to what is seems, in FORTH the word ABORT does not quit the interpreter, but starts an endless loop that reads a line
from the terminal, parses and interprets it. There is only one more step to transform the original Starflight kernel into a
general purpose FORTH interpreter.
It seems the authors patched a FORTH word named QUIT to alter its
behavior. QUIT is called by ABORT, and it is QUIT which actually
runs the read-parse-interpret loop. But in the original kernel the first word of QUIT was changed to BYE. When BYE is run the
interpreter exits. This means that the interpreter will exit when it reaches ABORT in the above definition. So I patched QUIT
to restore its original behavior and the interpreter gave me the default FORTH prompt:
FORTHOUGHT (P) (C) Copyright Fantasia Systems Inc. 1982,1983,1984 Version 2.52 for Binary Systems for the IBM PC ok
To be sure I ran some simple FORTH words. In this case I typed “2 3 + .”, which means “print the result
of 2 + 3″ and the reply was “5″, as expected:
FORTHOUGHT (P) (C) Copyright Fantasia Systems Inc. 1982,1983,1984 Version 2.52 for Binary Systems for the IBM PC ok 2 3 + . 5 ok
As a final test, at the prompt I executed the word LET-THERE-BE-STARFLIGHT and the game started normally.
This interpreter is fully functional, but there are some caveats. Because of space constraints (the whole interpreter had to
fit in a 64K segment) an overlay system was built into Starflight. While the STARFLT.COM kernel is always in memory,
code overlays stored in STARA.COM and STARB.COM are loaded and unloaded on demand. The FORTH dictionary is patched after
an overlay is loaded so that its words are linked to the kernel words. After an overlay is no longer needed, it is removed
from memory and the dictionary is restored to its original form. For
example, the code that handles the destruction of the Crystal
Planet is stored in a overlay, since it is needed only at the game finale.